/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package lcfgly.database.utils;

import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.Map;
import lcfgly.database.LSqlAutoBeanException;
import lcfgly.database.LSqlException;
import lcfgly.database.LSqlExtParamsException;
import lcfgly.utils.LTypeUtils;

/**
 * LDecodeObject
 * 自动解析LDataAnnotation注解的类
 * @author lcfgly
 * @Date 2015-1-29 14:22:47
 * @version 1.0
 */
public class LDecodeObject {

    //数据表前缀
    private String prefix="";

    public LDecodeObject(String prefix) {
        this.prefix = prefix;
    }
    
    public LDecodeObject(){}
    
    public void setPrefix(String prefix){
        this.prefix=prefix;
    }
    
    public String getPrefix(){
        if(prefix == null || "".equals(prefix.trim()))
            return "";
        else
            return prefix;
    }
    
    /**
     * 生成update语句
     * @param ob
     * @return 返回Object数组
     *      1:sql语句
     *      2:sql中的参数
     *      3:where语句（主键=值）返回后需要手动拼接，或拼接其他where条件
     *      4:where中的条件
     */
    public Object[] updateString(Object ob)throws LSqlException{
        Class cs=ob.getClass();
        LDataAnnotation da=ob.getClass().getAnnotation(LDataAnnotation.class);
        if(da == null)
            throw new LSqlExtParamsException(cs);
        String table=da.value();
        if(LTypeUtils.stringIsEmpty(table))
            throw new LSqlExtParamsException(cs);
        StringBuilder sb=new StringBuilder("UPDATE ");
        if(!LTypeUtils.stringIsEmpty(prefix))
            sb.append(prefix);
        sb.append(table).append(" SET ");
        Field[] fields=cs.getDeclaredFields();
        LinkedList<Object> args=new LinkedList<>();
        String swhere=null;
        Object owhere=null;
        for (Field field : fields) {
            field.setAccessible(true);
            LDataItemAnnotation dia=field.getAnnotation(LDataItemAnnotation.class);
            if(dia == null)
                continue;
            try {
                Object item=field.get(ob);
                String str=dia.item();
                if(LTypeUtils.stringIsEmpty(str))
                    str=field.getName();
                if(dia.notnull() && item == null)
                    throw new LSqlException(cs.getName()+"中"+field.getName()+"不能为空！");
                if(dia.primarykey()){
                    swhere=" WHERE "+str+" = ? ";
                    owhere=item;
                }else{
                    sb.append(str).append(" = ? ,");
                    args.add(item);
                }
            }catch (IllegalArgumentException | IllegalAccessException ex) {
                throw new LSqlExtParamsException(cs);
            }
        }
        sb.setLength(sb.length()-1);
        Object[] result=new Object[4];
        result[0]=sb.toString();
        result[1]=args;
        result[2]=swhere;
        result[3]=owhere;
        return result;
    }
    
    /**
     * 生成Insert语句
     * @param ob
     * @return Object数组
     *          1:sql语句
     *          2:语句中的参数
     */
    public Object[] insertString(Object ob)throws LSqlException{
        Class cs=ob.getClass();
        LDataAnnotation da=ob.getClass().getAnnotation(LDataAnnotation.class);
        if(da == null)
            throw new LSqlExtParamsException(cs);
        String table=da.value();
        if(LTypeUtils.stringIsEmpty(table))
            throw new LSqlExtParamsException(cs);
        StringBuilder sb=new StringBuilder("INSERT INTO ");
        if(!LTypeUtils.stringIsEmpty(prefix))
            sb.append(prefix);
        sb.append(table).append(" (");
        StringBuilder svalues=new StringBuilder(") VALUES ( ");
        LinkedList<Object> args=new LinkedList<>();
        Field[] fields=cs.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            LDataItemAnnotation dia=field.getAnnotation(LDataItemAnnotation.class);
            if(dia == null || dia.autokey())
                continue;
            try {
                Object item=field.get(ob);
                if(dia.notnull() && item  == null )
                    throw new LSqlException(cs.getName()+"中"+field.getName()+"不能为空！");
                String itemname=dia.item();
                if(LTypeUtils.stringIsEmpty(itemname))
                    itemname=field.getName();
                sb.append(itemname).append(",");
                svalues.append("?,");
                args.add(item);
            } catch (IllegalArgumentException | IllegalAccessException ex) {
                throw new LSqlExtParamsException(cs);
            }
        }
        sb.setLength(sb.length()-1);
        svalues.setLength(svalues.length()-1);
        sb.append(svalues).append(")");
        Object[] result=new Object[2];
        result[0]=sb.toString();
        result[1]=args;
        return result;
    }
    
    /**
     * 生成Select语句
     * @param cs
     * @return sql语句只生成了搜索字段和数据表（eg: SELECT items... FROM tablename
     */
    public String selectString(Class cs)throws LSqlException{
        LDataAnnotation da=(LDataAnnotation)cs.getAnnotation(LDataAnnotation.class);
        if (da == null)
            throw new LSqlExtParamsException(cs);
        String table=da.value();
        if(LTypeUtils.stringIsEmpty(table))
            throw new LSqlExtParamsException(cs);
        if(!LTypeUtils.stringIsEmpty(prefix))
            table=prefix+table;
        StringBuilder sb=new StringBuilder("SELECT ");
        Field[] fields=cs.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            LDataItemAnnotation dia=field.getAnnotation(LDataItemAnnotation.class);
            if(dia == null)
                continue;
            String itemname=dia.item();
            if(LTypeUtils.stringIsEmpty(itemname))
                itemname=field.getName();
            sb.append(table).append(".").append(itemname).append(",");
        }
        sb.setLength(sb.length()-1);
        sb.append(" FROM ").append(table);
        return sb.toString();
    }
    
    /**
     * 生成delete语句 delete from tablename where [pirmarykey] = ? 
     * @param ob
     * @return 返回Object数组
     *          1:sql语句
     *          2:语句中的参数
     * @throws LSqlException 
     */
    public Object[] deleteString(Object ob)throws LSqlException{
        Class cs=ob.getClass();
        LDataAnnotation da=ob.getClass().getAnnotation(LDataAnnotation.class);
        if (da == null)
            throw new LSqlExtParamsException(cs);
        String table=da.value();
        if(LTypeUtils.stringIsEmpty(table))
            throw new LSqlExtParamsException(cs);
        StringBuilder sb=new StringBuilder("DELETE FROM  ");
        if(!LTypeUtils.stringIsEmpty(prefix))
            sb.append(sb);
        Field[] fields=cs.getDeclaredFields();
        Object arg=null;
        for (Field field : fields) {
            field.setAccessible(true);
            LDataItemAnnotation dia=field.getAnnotation(LDataItemAnnotation.class);
            if(dia == null)
                continue;
            if(dia.primarykey()){
                String itemname=dia.item();
                if(LTypeUtils.stringIsEmpty(itemname))
                    itemname=field.getName();
                sb.append(" WHERE ").append(itemname).append(" = ? ");
                try {
                    arg=field.get(ob);
                } catch (IllegalArgumentException | IllegalAccessException ex) {
                    throw new LSqlExtParamsException(cs);
                }
                break;
            }
        }
        Object[] result=new Object[2];
        result[0]=sb.toString();
        result[1]=arg;
        return result;
    }
    
    /**
     * 通过反射设置实例
     * @param <T>
     * @param cs
     * @param rs
     * @return 
     */
    public <T> T setObject(Class<T> cs,Map<String,Object> rs)throws LSqlException{
        try {
            T result = cs.newInstance();
            Field[] fields=cs.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                LDataItemAnnotation dia=field.getAnnotation(LDataItemAnnotation.class);
                if(dia == null)
                    continue;
                String itemname=dia.item();
                if(LTypeUtils.stringIsEmpty(itemname))
                    itemname=field.getName();
                Object arg=rs.get(itemname);
                if(arg == null)
                    continue;
                field.set(result, arg);
            }
            return result;
        } catch (InstantiationException | IllegalAccessException ex) {
            throw new LSqlAutoBeanException(cs);
        }
    }
    
}
